use std::collections::HashMap;
use crate::errors::*;
use crate::rest::client::BinanceRestClient;
use crate::rest::trade_types::{CancelOrderRequestRaw, ModifyOrderRequestRaw, OrderRequestRaw, OrderResponse, OrderResponseRaw, QueryAllOrdersRequestRaw, QueryOpenOrdersRequestRaw, QueryOrderRequestRaw};
use crate::rest::{ChangeLeverageRequestRaw, ChangeLeverageResponse, ChangeLeverageResponseRaw, ChangeMarginTypeRequestRaw, ChangeMarginTypeResponse, ChangeMarginTypeResponseRaw, ChangePositionModeRequestRaw, ChangePositionModeResponse, ChangePositionModeResponseRaw, PositionRisk, PositionRiskRaw};
use crate::signer::sign;
use chrono::Utc;
use serde_urlencoded;

impl BinanceRestClient {
    /// 发送下单请求（结构化参数版本）
    pub async fn post_order(&self, req: &OrderRequestRaw) -> Result<OrderResponse> {
        // 将结构体转换为 urlencoded 字符串
        let mut query_str = serde_urlencoded::to_string(req)?;
        let timestamp = Utc::now().timestamp_millis();
        query_str += &format!("&timestamp={}", timestamp);
        let signature = sign(&self.config.secret_key, &query_str);
        let signed_query = format!("{}&signature={}", query_str, signature);

        // 请求 URL
        let url = format!("/fapi/v1/order?{}", signed_query);
        let resp = self.post(&url, &HashMap::<&str, String>::new(), true).await?;

        // 返回解析后的结构体
        let parsed: OrderResponseRaw = serde_json::from_str(&resp)?;
        let model = parsed.to_model().ok_or_else(|| BinanceError::Other("convert failed.".into()))?;
        Ok(model)
    }

    /// 修改订单（当前仅支持 LIMIT 类型订单）
    pub async fn modify_order(
        &self,
        req: &ModifyOrderRequestRaw,
    ) -> Result<OrderResponseRaw> {
        let mut query_str = serde_urlencoded::to_string(req)?;
        let signature = sign(&self.config.secret_key, &query_str);
        query_str = format!("{}&signature={}", query_str, signature);
        let url = format!("{}/fapi/v1/order?{}", self.config.rest_base_url(), query_str);
        let resp = self.put(&url, true).await?;
        let order: OrderResponseRaw = serde_json::from_str(&resp)?;
        Ok(order)
    }

    pub async fn cancel_order(&self, req: &CancelOrderRequestRaw) -> Result<OrderResponseRaw> {
        let mut query_str = serde_urlencoded::to_string(req)?;
        let signature = sign(&self.config.secret_key, &query_str);
        query_str.push_str(&format!("&signature={}", signature));

        let url = format!("{}/fapi/v1/order?{}", self.config.rest_base_url(), query_str);
        let resp = self.delete(&url, true).await?;

        let resp: OrderResponseRaw = serde_json::from_str(&resp)?;
        Ok(resp)
    }

    /// 查询订单状态（需传 symbol，order_id 或 orig_client_order_id 二选一）
    pub async fn query_order(&self, req: &QueryOrderRequestRaw) -> Result<OrderResponseRaw> {
        let mut query_str = serde_urlencoded::to_string(req)?;
        let signature = sign(&self.config.secret_key, &query_str);
        query_str = format!("{}&signature={}", query_str, signature);
        let url = format!("/fapi/v1/order?{}", query_str);
        let resp = self.get(&url, true).await?;
        let order: OrderResponseRaw = serde_json::from_str(&resp)?;
        Ok(order)
    }

    /// 查询账户历史订单（所有状态，支持时间范围与起始 order_id）
    pub async fn get_all_orders(&self, req: &QueryAllOrdersRequestRaw) -> Result<Vec<OrderResponseRaw>> {
        let mut query_str = serde_urlencoded::to_string(req)?;
        let signature = sign(&self.config.secret_key, &query_str);
        query_str = format!("{}&signature={}", query_str, signature);
        let url = format!("/fapi/v1/allOrders?{}", query_str);
        let resp = self.get(&url, true).await?;
        let orders: Vec<OrderResponseRaw> = serde_json::from_str(&resp)?;
        Ok(orders)
    }

    pub async fn get_open_orders(
        &self,
        req: &QueryOpenOrdersRequestRaw,
    ) -> Result<Vec<OrderResponseRaw>> {
        let mut query_str = serde_urlencoded::to_string(req)?;
        let signature = sign(&self.config.secret_key, &query_str);
        query_str = format!("{}&signature={}", query_str, signature);
        let url = format!("/fapi/v1/openOrders?{}", query_str);
        let resp = self.get(&url, true).await?;
        let orders: Vec<OrderResponseRaw> = serde_json::from_str(&resp)?;
        Ok(orders)
    }

    pub async fn get_position_risk(
        &self,
        symbol: Option<&str>,
    ) -> Result<Vec<PositionRisk>> {
        let mut query = format!("timestamp={}", Utc::now().timestamp_millis());
        if let Some(sym) = symbol {
            query += &format!("&symbol={}", sym);
        }
        let signature = sign(&self.config.secret_key, &query);
        let full_query = format!("{}&signature={}", query, signature);
        let url = format!("/fapi/v3/positionRisk?{}", full_query);
        let resp = self.get(&url, true).await?;
        let raws: Vec<PositionRiskRaw> = serde_json::from_str(&resp)?;
        Ok(raws.into_iter().filter_map(|r| r.to_model()).collect())
    }

    pub async fn change_leverage(
        &self,
        req: &ChangeLeverageRequestRaw,
    ) -> Result<ChangeLeverageResponse> {
        let mut query_str = serde_urlencoded::to_string(req)?;
        let signature = sign(&self.config.secret_key, &query_str);
        query_str = format!("{}&signature={}", query_str, signature);

        let url = format!("/fapi/v1/leverage?{}", query_str);
        let resp = self.post(&url, &HashMap::<&str, String>::new(), true).await?;

        let raw: ChangeLeverageResponseRaw = serde_json::from_str(&resp)?;
        let model = raw.to_model().ok_or_else(|| BinanceError::Other("leverage转换失败".into()))?;
        Ok(model)
    }

    /// POST /fapi/v1/marginType：设置保证金模式（ISOLATED / CROSSED）
    pub async fn change_margin_type(
        &self,
        req: &ChangeMarginTypeRequestRaw,
    ) -> Result<ChangeMarginTypeResponse> {
        let mut query_str = serde_urlencoded::to_string(req)?;
        let signature = sign(&self.config.secret_key, &query_str);
        query_str = format!("{}&signature={}", query_str, signature);

        let url = format!("/fapi/v1/marginType?{}", query_str);
        let resp = self.post(&url, &HashMap::<&str, String>::new(), true).await?;

        let raw: ChangeMarginTypeResponseRaw = serde_json::from_str(&resp)?;
        Ok(raw.to_model())
    }

    /// POST /fapi/v1/positionSide/dual：变更仓位模式（双向/单向）
    pub async fn change_position_mode(
        &self,
        req: &ChangePositionModeRequestRaw,
    ) -> Result<ChangePositionModeResponse> {
        let mut query_str = serde_urlencoded::to_string(req)?;
        let signature = sign(&self.config.secret_key, &query_str);
        query_str = format!("{}&signature={}", query_str, signature);

        let url = format!("/fapi/v1/positionSide/dual?{}", query_str);
        let resp = self.post(&url, &HashMap::<&str, String>::new(), true).await?;

        let raw: ChangePositionModeResponseRaw = serde_json::from_str(&resp)?;
        Ok(raw.to_model())
    }

}
